package utils;

import genetic_algorithm.Chromosome;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

/**
 * Type of return value of the genetic algorithm.
 * This type encapsulates the final population and
 * data to track each generation
 */
public class GAretVal {

	/**
	 * Holds the data for the generation- average fitness and
	 * best fitness
	 */
	public class GenerationData {
		
		public double bestFitness; // best fitness value of generation
		public double avgFitness; // average fitness value of generation
		
		/**
		 * Constructor- creates a new pair holding data for
		 * the generation
		 * @param bestFitness best fitness value
		 * @param avgFitness average fitness value
		 */
		public GenerationData(double bestFitness, double avgFitness) {
			super();
			this.bestFitness = bestFitness;
			this.avgFitness = avgFitness;
		}
	}
	
	/* 
	 * holds data for all generations of an execution of the genetic algorithm
	 * (i'th element is data for i'th generation)
	 */
	private List<GenerationData> executionData;
	
	// final population's chromosome with best fitness value
	private Chromosome optSolution;

	/**
	 * Constructor- creates a new object to hold the return value
	 * of the genetic algorithm
	 */
	public GAretVal() {
		super();
		executionData = new LinkedList<GenerationData>();
		optSolution = null;
	}
	
	/**
	 * Adds average fitness and best fitness for a new generation
	 * @param bestFitness best fitness value
	 * @param avgFitness average fitness value
	 */
	public void addGenData(double bestFitness, double avgFitness) {
		executionData.add(new GenerationData(bestFitness, avgFitness));
	}

	/**
	 * Returns best fitness value of indicated generation
	 * @param genNum number of wanted generation
	 * @return best fitness value of indicated generation
	 */
	public double getBestFitness(int genNum) {
		return executionData.get(genNum).bestFitness;
	}
	
	/**
	 * Returns average fitness value of indicated generation
	 * @param genNum number of wanted generation
	 * @return average fitness value of indicated generation
	 */
	public double getAvgFitness(int genNum) {
		return executionData.get(genNum).avgFitness;
	}
	
	/**
	 * Sets chromosome which represents problem's optimized solution
	 * @param solution final population's chromosome with best fitness value
	 */
	public void setSolution(Chromosome solution) {
		this.optSolution = solution;
	}
	
	/**
	 * Returns the optimized solution 
	 * @return solution member
	 */
	public Chromosome getOptSolution() {
		return optSolution;
	}
	
	public void createsCsvFiles(String fileName)
	{
		FileWriter writer = null;
		try {
			writer = new FileWriter(new File(fileName+".csv"));
			
			writer.write(",Best Fitness, Avarge fitness\n");
			double prevFit = -1, prevAva = -1;
			int i = 0;
			for(GenerationData data : executionData)
			{
				if(data.bestFitness != prevFit || data.avgFitness != prevAva)
				{					
					writer.write(i+","+data.bestFitness+","+data.avgFitness+"\n");
					prevAva = data.avgFitness; prevFit = data.bestFitness;
				}
				i++;
			}
			writer.close();
		} catch (IOException e) {		
			e.printStackTrace();
		}
	}
}
